#include "File.h"

File::File(string fileName, int versionNum){
    _fileName = fileName;
    _versionNum = versionNum;
    for(int i = 0; i <= versionNum; i++){
        Version * newVersion = new Version();
        newVersion->_host = NULL;
        newVersion->_currentTimestamp = 0;
        newVersion->_networkTimestamp = 0;
        newVersion->_hasLocalCopy = false;
        newVersion->_modified = false;
        newVersion->_status = File::NOCOPY;
        _versions.push_back(newVersion);
    }
}

File::~File(){
    while(!_versions.empty()){
        Version * temp = _versions.back();
        _versions.pop_back();
        if(temp->_host != NULL){
            delete temp->_host;
        }
        delete temp;
    }
}

// accessors
string File::fileName(){
    string result = _fileName;
    return result;
}

// returns the current largest version number
int File::versionNum(){
    int result = _versionNum;
    return result;
}

Host * File::host(int versionNum){
    return _versions[versionNum]->_host;
}

int File::networkTimestamp(int versionNum){
    int result = errVersionNotFound;
    if(versionNum <= _versionNum){
        result = _versions[versionNum]->_networkTimestamp;
    }
    return result;
}


// returns safe for uptodate, or errNotUpToDate for not
int File::isVersionUpToDate(int versionNum){
    int status = errNotUpToDate;
    if(_versions[versionNum]->_currentTimestamp == _versions[versionNum]->_networkTimestamp){
        status = SAFE;
    }
    return status;
}

bool File::isAvailable(int versionNum){
    bool available = true;
    if(host(versionNum) == NULL){
        // check if there's a local copy
        if(!hasLocalCopy(versionNum)){
            available = false;
        }
    }
    return available;
}



int File::removedLocalCopy(int versionNum){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_hasLocalCopy = false;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

bool File::isModified(int versionNum){
    bool result = _versions[versionNum]->_modified;
    return result;
}

bool File::hasLocalCopy(int versionNum){
    bool result = _versions[versionNum]->_hasLocalCopy;
    return result;
}

File::Status File::status(int versionNum){
    File::Status result = _versions[versionNum]->_status;
    return result;
}

bool File::isVersionInTransit(int versionNum){
    bool result = false;
    if(_versions[versionNum]->_status == INTRANSIT){
        result = true;
    }
    return result;
}

// some manipulations
int File::setHost(int versionNum, Host * host){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_host = host;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::setModified(bool isModified, int versionNum){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_modified = isModified;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::setStatus(File::Status newStatus, int versionNum){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_status = newStatus;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::setVersionInTransit(int versionNum){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_status = INTRANSIT;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

// a new version was tagged
int File::addVersion(int versionNum, Host * host, int currentTimestamp){
    int status = SAFE;
    if(versionNum == _versionNum+1){
        _versionNum++;
        Version * newVersion = new Version();
        newVersion->_host = host;
        newVersion->_currentTimestamp = 0;
        newVersion->_networkTimestamp = currentTimestamp;
        newVersion->_hasLocalCopy = false;
        newVersion->_modified = false;
        newVersion->_status = File::NOCOPY;
        _versions.push_back(newVersion);
    }else{
        status = errInvalidVersion;
    }
    return status;
}

int File::updateTimestamp(int versionNum, Host * host, int networkTimestamp){
    int status = SAFE;
    if(versionNum <= _versionNum){
        if(_versions[versionNum]->_networkTimestamp <= networkTimestamp){
            delete _versions[versionNum]->_host;
            if(host != NULL){
                DBG_PRINTF(("new host %s:%i for file %s version %i\n", host->ip().c_str(), host->port(), _fileName.c_str(), versionNum));
            }else{
                DBG_PRINTF(("new host is NULL\n"));
            }
            _versions[versionNum]->_host = host;
            _versions[versionNum]->_networkTimestamp = networkTimestamp;
            _versions[versionNum]->_status = NOTREADY;
        }
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::updateVersion(int versionNum, int currentTimestamp){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_currentTimestamp = currentTimestamp;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::receivedLocalCopy(int versionNum){
    int status = SAFE;
    if(versionNum <= _versionNum){
        _versions[versionNum]->_hasLocalCopy = true;
    }else{
        status = errVersionNotFound;
    }
    return status;
}

int File::deleteFile(int timestamp){
    int status = SAFE;
    for(unsigned int i = 0; i < _versions.size(); i++){
        setStatus(DELETED, i);
        _versions[i]->_currentTimestamp = timestamp;
        _versions[i]->_networkTimestamp = timestamp;
        _versions[i]->_hasLocalCopy = false;
        _versions[i]->_host = NULL;
        _versions[i]->_status = DELETED;
    }
    return status;
}

